package org.ehe.business.step.controller;

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.ehe.business.step.domain.*;
import org.ehe.business.step.domain.DTO.StepAnalysisDTO;
import org.ehe.business.step.service.EnhancedSTEPAnalyzerService;
import org.ehe.business.step.service.STEPAnalyzerService;
import org.ehe.business.step.service.StepAnalysisService;
import org.ehe.common.core.BaseController;
import org.ehe.common.core.domain.R;
import org.ehe.common.log.annotation.Log;
import org.ehe.common.log.enums.BusinessType;
import org.ehe.system.domain.vo.SysOssVo;
import org.ehe.system.service.ISysOssService;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.Resource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.CompletableFuture;

/**
 * STEP文件分析
 * @author :zhangnn
 * @className :STEPController
 * @description: 提供STEP文件上传、分析、PDF生成和制造估算等功能
 * @date 2025-08-05 15:01:12
 */
@Slf4j
@RestController
@RequestMapping("/step")
@RequiredArgsConstructor
@Validated
@CrossOrigin(origins = "*", maxAge = 3600)
public class STEPController extends BaseController {

    private final STEPAnalyzerService stepAnalyzerService;
    private final EnhancedSTEPAnalyzerService enhancedSTEPAnalyzerService;

    private final StepAnalysisService analysisService;
    private final ISysOssService ossService;

    @Value("${step.pdf.path}")
    private String savePdfUrl;

    /**
     * 上传STEP文件并进行几何分析、制造估算，生成PDF报告
     * @param file  STEP文件（.step或.stp格式）
     * @param analysisLevel 分析选项
     * @param generateDrawing 是否生成工程图
     * @param materialType 材料类型
     * @return
     */
    @Log(title = "STEP文件分析", linkType = "step", businessType = BusinessType.INSERT, idField = "requestId", nameField = "fileName")
    @PostMapping(value = "/analyze", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
    public R<STEPAnalysisResult> analyzeSTEPFile(@NotNull MultipartFile file,
                                                 String analysisLevel,
                                                 boolean generateDrawing,
                                                 String materialType) {

        String requestId = UUID.randomUUID().toString().substring(0, 8);
        log.info("[{}] 开始处理STEP文件分析请求 - 文件名: {}, 大小: {} bytes, 分析级别: {}",
            requestId, file.getOriginalFilename(), file.getSize(), analysisLevel);

        try {
            // 1. 参数验证
            ValidationResult validation = validateUploadFile(file);
            if (!validation.isValid()) {
                log.warn("[{}] 文件验证失败: {}", requestId, validation.getErrorMessage());
                return R.fail(validation.getErrorMessage());
            }

            // 2. 执行分析
            STEPAnalysisResult analysisResult;
            if ("ADVANCED".equalsIgnoreCase(analysisLevel)) {
                analysisResult = performAdvancedAnalysis(file, materialType, requestId);
            } else {
                analysisResult = performBasicAnalysis(file, requestId);
            }

            //分析文件上传到OSS
            File file1 = new File(analysisResult.getPdfReportPath());
            SysOssVo upload = ossService.upload(file1);

            // 3. 设置响应数据
            StepAnalysisDTO dto = convertResultToDto(analysisResult);
            dto.setResultJson(String.valueOf(analysisResult));
            if(!Objects.isNull(upload)){
                dto.setOssId(String.valueOf(upload.getOssId()));
            }
            analysisService.create(dto);
            return R.ok("STEP文件分析完成", analysisResult);

        } catch (IOException e) {
            log.error("[{}] 文件IO异常", requestId, e);
            return R.fail("文件处理失败，请检查文件完整性");
        } catch (Exception e) {
            log.error("[{}] 系统异常", requestId, e);
            return R.fail("系统内部错误，请稍后重试");
        }
    }

    /**
     * 异步分析STEP文件
     */
    @Log(title = "STEP文件异步分析", linkType = "step", businessType = BusinessType.INSERT, idField = "taskId", nameField = "fileName")
    @PostMapping("/analyzeAsync")
    @Operation(summary = "异步分析STEP文件", description = "异步处理大型STEP文件，返回任务ID用于查询进度")
    public R<AsyncAnalysisResponse> analyzeSTEPFileAsync(
        @RequestParam("file") @NotNull MultipartFile file,
        @RequestParam(value = "analysisLevel", defaultValue = "BASIC") String analysisLevel,
        @RequestParam(value = "callbackUrl", required = false) String callbackUrl) {

        String taskId = UUID.randomUUID().toString();
        log.info("创建异步分析任务: {}, 文件: {}", taskId, file.getOriginalFilename());

        AsyncAnalysisResponse response = new AsyncAnalysisResponse();
        response.setTaskId(taskId);
        response.setStatus("PROCESSING");
        response.setMessage("分析任务已创建，正在处理中");
        response.setCreatedAt(LocalDateTime.now());
        response.setStatusCheckUrl("/step/taskStatus/" + taskId);

        // 异步执行分析
        CompletableFuture.runAsync(() -> {
            try {
                log.info("开始异步处理任务: {}", taskId);
                performAsyncAnalysis(file, analysisLevel, taskId, callbackUrl);
            } catch (Exception e) {
                log.error("异步任务执行失败: {}", taskId, e);
            }
        });

        return R.ok("分析任务已创建", response);
    }

    /**
     * 查询异步任务状态
     */
    @GetMapping("/taskStatus/{taskId}")
    @Operation(summary = "查询任务状态", description = "查询异步分析任务的执行状态")
    public R<TaskStatusResponse> getTaskStatus(@PathVariable @NotBlank String taskId) {

        log.debug("查询任务状态: {}", taskId);

        TaskStatusResponse response = new TaskStatusResponse();
        response.setTaskId(taskId);
        response.setStatus("COMPLETED");
        response.setProgress(100);
        response.setMessage("分析完成");
        response.setUpdatedAt(LocalDateTime.now());

        if ("COMPLETED".equals(response.getStatus())) {
            response.setDownloadUrl("/step/downloadReport?taskId=" + taskId);
        }

        return R.ok("查询任务状态成功", response);
    }

    /**
     * 下载PDF分析报告
     */
    @GetMapping("/downloadReport")
    @Operation(summary = "下载PDF报告", description = "下载生成的PDF分析报告")
    public ResponseEntity<Resource> downloadReport(
        @Parameter(description = "报告ID")
        @RequestParam(value = "reportId", required = false) String reportId,

        @Parameter(description = "任务ID")
        @RequestParam(value = "taskId", required = false) String taskId,

        @Parameter(description = "报告路径")
        @RequestParam(value = "path", required = false) String reportPath) {

        try {
            String actualPath = determineReportPath(reportId, taskId, reportPath);
            if (actualPath == null) {
                log.warn("无效的下载请求 - reportId: {}, taskId: {}, path: {}", reportId, taskId, reportPath);
                return ResponseEntity.badRequest().build();
            }

            File reportFile = new File(actualPath);
            if (!reportFile.exists() || !reportFile.isFile()) {
                log.warn("报告文件不存在: {}", actualPath);
                return ResponseEntity.notFound().build();
            }

            // 安全检查：确保文件在允许的目录内
            if (!isFileInAllowedDirectory(reportFile)) {
                log.warn("尝试访问不允许的文件路径: {}", actualPath);
                return ResponseEntity.status(HttpStatus.FORBIDDEN).build();
            }

            Resource resource = new FileSystemResource(reportFile);
            String fileName = reportFile.getName();

            log.info("下载报告文件: {}, 大小: {} bytes", fileName, reportFile.length());

            return ResponseEntity.ok()
                .header(HttpHeaders.CONTENT_DISPOSITION,
                    "attachment; filename=\"" + fileName + "\"")
                .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_PDF_VALUE)
                .header(HttpHeaders.CONTENT_LENGTH, String.valueOf(reportFile.length()))
                .body(resource);

        } catch (Exception e) {
            log.error("下载报告失败", e);
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
        }
    }

    /**
     * 获取分析历史记录列表
     */
    @PostMapping("/list")
    @Operation(summary = "获取分析历史", description = "获取STEP文件分析历史记录")
    public R<List<AnalysisHistoryItem>> getAnalysisHistory(@RequestBody AnalysisHistoryQuery query) {

        log.debug("查询分析历史 - page: {}, size: {}, userId: {}",
            query.getPage(), query.getSize(), query.getUserId());

        // 这里应该从数据库查询实际的历史记录
        List<AnalysisHistoryItem> history = new ArrayList<>();
        // 模拟数据
        AnalysisHistoryItem item = new AnalysisHistoryItem();
        item.setId("hist_001");
        item.setFileName("sample.step");
        item.setAnalysisTime(LocalDateTime.now().minusHours(2));
        item.setComplexity("中等");
        item.setStatus("COMPLETED");
        history.add(item);

        return R.ok(history);
    }

    // ========== 私有辅助方法 ==========

    private ValidationResult validateUploadFile(MultipartFile file) {
        if (file == null || file.isEmpty()) {
            return ValidationResult.invalid("文件不能为空");
        }

        String fileName = file.getOriginalFilename();
        if (fileName == null) {
            return ValidationResult.invalid("文件名不能为空");
        }

        String lowerFileName = fileName.toLowerCase();
        if (!lowerFileName.endsWith(".step") && !lowerFileName.endsWith(".stp")) {
            return ValidationResult.invalid("只支持STEP格式文件（.step或.stp）");
        }

        if (file.getSize() > 100 * 1024 * 1024) { // 100MB
            return ValidationResult.invalid("文件大小不能超过100MB");
        }

        return ValidationResult.valid();
    }

    private STEPAnalysisResult performBasicAnalysis(MultipartFile file, String requestId) throws Exception {
        log.debug("[{}] 执行基础分析", requestId);
        return stepAnalyzerService.analyzeSTEPFile(file);
    }

    private STEPAnalysisResult performAdvancedAnalysis(MultipartFile file, String materialType, String requestId) throws IOException {
        log.debug("[{}] 执行高级分析，材料类型: {}", requestId, materialType);
        // 保存文件到临时目录
        Object[] result = saveTempFile(file);
        File tempFile = (File) result[0];
        String fileName = (String) result[1];
        try {
            return enhancedSTEPAnalyzerService.enhancedAnalysis(tempFile,fileName);
        } finally {
            // 清理临时文件
            if (tempFile.exists()) {
                tempFile.delete();
            }
        }
    }

    private void performAsyncAnalysis(MultipartFile file, String analysisLevel, String taskId, String callbackUrl) {
        // 异步分析的实际实现
        // 这里应该包含状态更新逻辑
    }

    private Object[] saveTempFile(MultipartFile file) throws IOException {
        String fileName = file.getOriginalFilename();
        String tempFileName = System.currentTimeMillis() + "_" + fileName;
        File tempFile = new File(savePdfUrl, tempFileName);
        file.transferTo(tempFile);
        return new Object[]{tempFile, fileName};
    }

    private String extractReportId(String pdfPath) {
        if (pdfPath == null) return null;
        return new File(pdfPath).getName().replaceAll("\\.[^.]+$", "");
    }

    private String determineReportPath(String reportId, String taskId, String path) {
        if (path != null && !path.trim().isEmpty()) {
            return path;
        }
        if (reportId != null) {
            return "output/" + reportId + ".pdf";
        }
        if (taskId != null) {
            return "output/task_" + taskId + ".pdf";
        }
        return null;
    }

    private boolean isFileInAllowedDirectory(File file) {
        try {
            String canonicalPath = file.getCanonicalPath();
            String allowedPath = new File("output/").getCanonicalPath();
            return canonicalPath.startsWith(allowedPath);
        } catch (IOException e) {
            return false;
        }
    }

    // ========== 内部类 ==========

    private static class ValidationResult {
        private final boolean valid;
        private final String errorMessage;

        private ValidationResult(boolean valid, String errorMessage) {
            this.valid = valid;
            this.errorMessage = errorMessage;
        }

        public static ValidationResult valid() {
            return new ValidationResult(true, null);
        }

        public static ValidationResult invalid(String message) {
            return new ValidationResult(false, message);
        }

        public boolean isValid() { return valid; }
        public String getErrorMessage() { return errorMessage; }
    }


    /**
     * 将STEPAnalysisResult完整复制到StepAnalysisDTO
     */
    public StepAnalysisDTO convertResultToDto(STEPAnalysisResult result) {
        if (result == null) {
            return null;
        }
        StepAnalysisDTO dto = new StepAnalysisDTO();

        // 1. 复制基本信息（字段名和类型兼容的部分）
        dto.setFileName(result.getFileName());
        dto.setFileSize(result.getFileSize()); // long -> Long（自动兼容）
        dto.setAnalysisTime(result.getAnalysisTime());
        dto.setDescription(result.getDescription());
        dto.setCreationInfo(result.getCreationInfo());
        dto.setUnit(result.getUnit());
        dto.setComplexity(result.getComplexity());
        dto.setRequestId(result.getRequestId());
        // 处理类型不匹配：Long -> Integer（需判断是否超出范围）
        if (result.getProcessingTimeMs() != null) {
            dto.setProcessingTimeMs(result.getProcessingTimeMs().intValue());
        }

        // 2. 处理几何分析（嵌套对象GeometryAnalysis -> 扁平字段）
        // 假设GeometryAnalysis包含以下字段：boundingBox、dimensions、surfaceTypes等
        GeometryAnalysis geometry = result.getGeometryAnalysis();
        if (geometry != null) {
            dto.setBoundingBox(Arrays.asList(Arrays.toString(geometry.getBoundingBox()))); // 假设返回List<BigDecimal>
            dto.setDimensions(geometry.getDimensions());
            dto.setSurfaceTypes(geometry.getSurfaceTypes()); // 假设返回Map<String, Integer>
            dto.setSurfaceComplexityScore(geometry.getSurfaceComplexityScore());
            dto.setMachiningFeatures(geometry.getMachiningFeatures()); // 假设返回List<String>
            dto.setFeatureDetails(geometry.getFeatureDetails()); // 假设返回Map<String, String>
            dto.setEstimatedVolume(geometry.getEstimatedVolume());
            dto.setVolumeUnit(geometry.getVolumeUnit());
            dto.setSurfaceArea(geometry.getSurfaceArea());
            dto.setToleranceInfo(geometry.getToleranceInfo());
        }
        // 几何实体信息（类型兼容：Map<String, Integer> -> Map<String, Object>）
        dto.setGeometricEntities(result.getGeometricEntities());

        // 3. 复制材料信息（字段名和类型兼容）
        dto.setMaterials(result.getMaterials()); // List<String> -> List<String>
        dto.setMaterialType(result.getMaterialType());
        // 类型兼容：Map<String, String> -> Map<String, Object>
        dto.setMaterialProperties(result.getMaterialProperties());

        // 4. 处理制造估算（嵌套对象ManufacturingEstimate -> 扁平字段）
        // 假设ManufacturingEstimate包含以下字段：estimatedDays、machiningHours等
        ManufacturingEstimate manufacturing = result.getManufacturingEstimate();
        if (manufacturing != null) {
            dto.setEstimatedDays(manufacturing.getEstimatedDays());
            dto.setMachiningHours(manufacturing.getMachiningHours());
            dto.setEstimatedCost(manufacturing.getEstimatedCost());
            dto.setRecommendedProcesses(manufacturing.getRecommendedProcesses()); // List<String>
            dto.setProcessTimeBreakdown(manufacturing.getProcessTimeBredown()); // Map<String, BigDecimal>
            dto.setCostBreakdown(manufacturing.getCostBreakdown()); // Map<String, BigDecimal>
            dto.setEstimatedMaterialVolume(manufacturing.getEstimatedMaterialVolume());
            dto.setRawMaterialVolume(manufacturing.getRawMaterialVolume());
            dto.setMaterialUtilization(manufacturing.getMaterialUtilization());
            dto.setDifficultyLevel(manufacturing.getDifficultyLevel());
            dto.setDifficultyScore(manufacturing.getDifficultyScore());
            dto.setRiskLevel(manufacturing.getRiskLevel());
            dto.setPrecisionLevel(manufacturing.getPrecisionLevel());
            dto.setSpecialRequirements(manufacturing.getSpecialRequirements()); // List<String>
            dto.setRequiredEquipment(manufacturing.getRequiredEquipment()); // List<String>
            dto.setMinMachineSize(manufacturing.getMinMachineSize());
        }

        // 5. 复制质量评估信息
        dto.setQualityIssues(result.getQualityIssues()); // List<String> -> List<String>
        dto.setRecommendations(result.getRecommendations()); // List<String> -> List<String>
        dto.setQualityScore(result.getQualityScore()); // int -> Integer（自动兼容）

        // 6. 复制文件路径和元数据
        dto.setPdfReportPath(result.getPdfReportPath());
        dto.setTechnicalDrawingPath(result.getTechnicalDrawingPath());
        dto.setModelPreviewPath(result.getModelPreviewPath());
        dto.setCadSoftware(result.getCadSoftware());
        dto.setStepVersion(result.getStepVersion());
        dto.setMetadata(result.getMetadata()); // Map<String, Object> -> Map<String, Object>

        return dto;
    }
}
